package com.lzqinga.service.storage;

import com.lzqinga.model.VideoSegment;
import com.lzqinga.service.VideoGeneratorService;
import com.lzqinga.util.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Slf4j
@Service
public class VideoSegmentService {

    @Autowired
    private LocalStorageService storageService;

    @Value("${ffmpeg.path:ffmpeg}")
    private String ffmpegPath;

    @Value("${app.video.width:1920}")
    private Integer videoWidth;

    @Value("${app.video.height:1080}")
    private Integer videoHeight;

    @Value("${app.video.fps:25}")
    private Integer videoFps;

    @Value("${app.video.subtitle.enabled:false}") // 先禁用字幕
    private Boolean enableSubtitles;

    @Value("${app.video.subtitle.font-size:48}")
    private Integer subtitleFontSize;

    @Value("${app.video.subtitle.font-file:}")
    private String subtitleFontFile;

    @Value("${app.video.subtitle.font-color:white}")
    private String subtitleFontColor;

    @Value("${app.video.subtitle.background-color:black@0.5}")
    private String subtitleBackgroundColor;

    @Value("${app.video.subtitle.position:bottom}")
    private String subtitlePosition;

    private static final String OS = System.getProperty("os.name").toLowerCase();
    private static final boolean IS_WINDOWS = OS.contains("win");

    /**
     * 创建视频片段 - 完全重写版本
     */
    public String createVideoSegment(VideoGeneratorService.Segment segment) {
        // 生成临时文件路径
        String tempVideoPath = generateTempFilePath("mp4");

        try {
            log.info("开始创建视频片段，音频: {}, 图片: {}", segment.audioPath, segment.imagePath);

            // 验证文件存在
            validateFile("音频文件", segment.audioPath);
            validateFile("图片文件", segment.imagePath);

            // 获取音频时长
            double duration = getAudioDurationSimple(segment.audioPath);
            log.info("音频时长: {} 秒", duration);

            // 构建并执行命令
            String command;
            if (enableSubtitles && segment.content != null && !segment.content.trim().isEmpty()) {
                // 使用带字幕的命令
                command = buildCommandWithSubtitle(segment.imagePath, segment.audioPath,
                        segment.content, tempVideoPath, duration);
            } else {
                // 使用简单命令
                command = buildSimpleCommand(segment.imagePath, segment.audioPath, tempVideoPath, duration);
            }
            executeCommandSimple(command);

            // 验证生成的视频文件
            validateFile("视频文件", tempVideoPath);

            log.info("视频片段创建成功: {}", tempVideoPath);
            return tempVideoPath;

        } catch (Exception e) {
            log.error("创建视频片段失败", e);
            cleanupFile(tempVideoPath);
            throw new RuntimeException("创建视频片段失败: " + e.getMessage(), e);
        }
    }

    /**
     * 构建带字幕的FFmpeg命令
     */
    private String buildCommandWithSubtitle(String imagePath, String audioPath, String subtitleText,
                                            String outputPath, double duration) {
        // 转义字幕文本中的特殊字符
        String escapedText = escapeSubtitleText(subtitleText);

        // 构建字幕滤镜
        String subtitleFilter = buildSubtitleFilter(escapedText);

        // 构建完整的滤镜链
        String filterChain = String.format(
                "scale=%d:%d:force_original_aspect_ratio=decrease," +
                        "pad=%d:%d:(ow-iw)/2:(oh-ih)/2:color=black," +
                        "%s",
                videoWidth, videoHeight, videoWidth, videoHeight, subtitleFilter
        );

        return String.format(
                "%s -y -loop 1 -i \"%s\" -i \"%s\" -t %.2f " +
                        "-vf \"%s\" " +
                        "-c:v libx264 -pix_fmt yuv420p -c:a aac -shortest -r %d \"%s\"",
                ffmpegPath, imagePath, audioPath, duration, filterChain, videoFps, outputPath
        );
    }

    /**
     * 转义字幕文本中的特殊字符
     */
    private String escapeSubtitleText(String text) {
        if (text == null) return "";

        // 转义FFmpeg drawtext滤镜的特殊字符
        return text.replace(":", "\\:")
                .replace("'", "\\'")
                .replace(",", "\\,")
                .replace(";", "\\;")
                .replace("[", "\\[")
                .replace("]", "\\]")
                .replace("{", "\\{")
                .replace("}", "\\}")
                .replace("(", "\\(")
                .replace(")", "\\)")
                .replace("\"", "\\\"");
    }

    /**
     * 构建字幕滤镜
     */
    private String buildSubtitleFilter(String text) {
        StringBuilder filter = new StringBuilder("drawtext=");

        // 文本内容
        filter.append("text='").append(text).append("'");

        // 字体设置 - 使用转义的字体路径
        String escapedFontFile = escapeFontFilePath(subtitleFontFile);
        filter.append(":fontfile='").append(escapedFontFile).append("'");

        // 字体大小和颜色
        filter.append(":fontsize=").append(subtitleFontSize);
        filter.append(":fontcolor=").append(subtitleFontColor);

        // 背景框
        filter.append(":box=1:boxcolor=").append(subtitleBackgroundColor).append(":boxborderw=5");

        // 位置
        String position = calculateSubtitlePosition();
        filter.append(":").append(position);

        return filter.toString();
    }

    /**
     * 转义字体文件路径
     */
    private String escapeFontFilePath(String fontPath) {
        if (fontPath == null) return "";

        // 转义路径中的特殊字符
        return fontPath.replace(":", "\\:")
                .replace("'", "\\'")
                .replace(",", "\\,")
                .replace(";", "\\;");
    }

    /**
     * 计算字幕位置
     */
    private String calculateSubtitlePosition() {
        switch (subtitlePosition.toLowerCase()) {
            case "top":
                return "x=(w-text_w)/2:y=50";
            case "middle":
                return "x=(w-text_w)/2:y=(h-text_h)/2";
            case "bottom":
            default:
                return "x=(w-text_w)/2:y=h-text_h-50";
        }
    }

    /**
     * 生成临时文件路径
     */
    private String generateTempFilePath(String extension) {
        String fileName = "temp_video_" + UUID.randomUUID() + "." + extension;
        fileName = FileUtil.getDataFilePath(fileName, "data\\temp");

        return fileName;
    }

    /**
     * 验证文件存在性和有效性
     */
    private void validateFile(String fileType, String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new RuntimeException(fileType + "不存在: " + filePath);
        }
        if (file.length() == 0) {
            throw new RuntimeException(fileType + "为空文件: " + filePath);
        }
        log.info("{}验证通过: {} ({} bytes)", fileType, filePath, file.length());
    }

    /**
     * 获取音频时长 - 最简单可靠的方法
     */
    private double getAudioDurationSimple(String audioPath) {
        try {
            // 直接调用ffmpeg获取信息
            String command = String.format("\"%s\" -i \"%s\"", ffmpegPath, audioPath);

            ProcessBuilder pb = new ProcessBuilder("cmd", "/c", command);
            pb.redirectErrorStream(true);
            Process process = pb.start();

            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.contains("Duration:")) {
                    // 解析: Duration: 00:00:08.82, start: 0.000000, bitrate: 48 kb/s
                    String durationStr = line.split("Duration:")[1].split(",")[0].trim();
                    return parseDurationToSeconds(durationStr);
                }
            }

            process.waitFor();
            return 8.0; // 默认值

        } catch (Exception e) {
            log.warn("获取音频时长失败，使用默认值5秒: {}", e.getMessage());
            return 5.0;
        }
    }

    /**
     * 解析时长字符串为秒数
     */
    private double parseDurationToSeconds(String durationStr) {
        try {
            // 格式: HH:MM:SS.mmm
            String[] parts = durationStr.split(":");
            if (parts.length == 3) {
                double hours = Double.parseDouble(parts[0]);
                double minutes = Double.parseDouble(parts[1]);
                double seconds = Double.parseDouble(parts[2]);
                double totalSeconds = hours * 3600 + minutes * 60 + seconds;
                log.debug("解析时长: {} -> {} 秒", durationStr, totalSeconds);
                return totalSeconds;
            }
        } catch (Exception e) {
            log.warn("解析时长失败: {}", durationStr);
        }
        return 5.0;
    }

    /**
     * 构建最简单的FFmpeg命令
     */
    private String buildSimpleCommand(String imagePath, String audioPath, String outputPath, double duration) {
        // 使用最简单的参数，避免任何复杂滤镜
        return String.format(
                "%s -y -loop 1 -i \"%s\" -i \"%s\" -t %.2f -c:v libx264 -pix_fmt yuv420p -c:a aac -shortest \"%s\"",
                ffmpegPath, imagePath, audioPath, duration, outputPath
        );
    }

    /**
     * 执行命令 - 简化版本
     */
    private void executeCommandSimple(String command) {
        log.info("执行FFmpeg命令: {}", command);

        try {
            ProcessBuilder pb;
            if (IS_WINDOWS) {
                pb = new ProcessBuilder("cmd", "/c", command);
            } else {
                pb = new ProcessBuilder("bash", "-c", command);
            }

            // 合并输出流
            pb.redirectErrorStream(true);

            Process process = pb.start();

            // 读取输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            StringBuilder output = new StringBuilder();
            String line;

            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
                log.debug("FFmpeg: {}", line);
            }

            int exitCode = process.waitFor();

            if (exitCode != 0) {
                log.error("FFmpeg执行失败，退出码: {}", exitCode);
                log.error("FFmpeg输出: {}", output.toString());
                throw new RuntimeException("FFmpeg命令执行失败，退出码: " + exitCode);
            }

            log.info("FFmpeg命令执行成功");

        } catch (Exception e) {
            throw new RuntimeException("执行FFmpeg命令失败: " + e.getMessage(), e);
        }
    }

    /**
     * 清理文件
     */
    private void cleanupFile(String filePath) {
        if (filePath == null) return;

        try {
            Path path = Paths.get(filePath);
            if (Files.exists(path)) {
                Files.delete(path);
                log.info("清理临时文件: {}", filePath);
            }
        } catch (Exception e) {
            log.warn("清理文件失败: {}", filePath, e);
        }
    }

    /**
     * 测试FFmpeg是否正常工作
     */
    public String testFfmpeg() {
        try {
            String command = String.format("\"%s\" -version", ffmpegPath);

            ProcessBuilder pb = new ProcessBuilder("cmd", "/c", command);
            pb.redirectErrorStream(true);
            Process process = pb.start();

            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            StringBuilder output = new StringBuilder();
            String line;

            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
            }

            int exitCode = process.waitFor();

            return String.format("退出码: %d\n输出:\n%s", exitCode, output.toString());

        } catch (Exception e) {
            return "测试失败: " + e.getMessage();
        }
    }

    /**
     * 测试音频文件
     */
    public String testAudioFile(String audioPath) {
        try {
            String command = String.format("\"%s\" -i \"%s\"", ffmpegPath, audioPath);

            ProcessBuilder pb = new ProcessBuilder("cmd", "/c", command);
            pb.redirectErrorStream(true);
            Process process = pb.start();

            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            StringBuilder output = new StringBuilder();
            String line;

            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
            }

            int exitCode = process.waitFor();

            return String.format("退出码: %d\n输出:\n%s", exitCode, output.toString());

        } catch (Exception e) {
            return "测试失败: " + e.getMessage();
        }
    }
}